#include "glwidget.h"

#include <QDebug>
#include <QGLShaderProgram>
#include <QImageReader>
#include <QVector>
#include <QVector3D>
#include <QVector2D>

#include "gltexture.h"

GLWidget::GLWidget(QWidget *parent)
    : QGLWidget(parent)
{
}

GLWidget::~GLWidget()
{
    
}

void GLWidget::loadTextures()
{
    QPixmap basePixmap(":images/basemap.png");
    QImage baseGlImg = QGLWidget::convertToGLFormat(basePixmap.toImage());
    GLubyte *pixels = baseGlImg.bits();
    GLTexture *texture = new GLTexture(pixels, baseGlImg.width(), baseGlImg.height(), GLTexture::FormatRGBA, GLTexture::Target2D);
    _userObject.setBaseMapTexture(QSharedPointer<GLTexture>(texture));
    texture->setMagnificationFilter();
    texture->setMinificationFilter(GLTexture::MinificationLinear);
    texture->setSCoordinateWrap(GLTexture::WrapClampToEdge);
    texture->setTCoordinateWrap(GLTexture::WrapClampToEdge);

    QPixmap lightPixmap(":images/lightmap.png");
    QImage lightGlImg = QGLWidget::convertToGLFormat(lightPixmap.toImage());
    GLTexture *lightTexture = new GLTexture(lightGlImg.bits(), lightGlImg.width(), lightGlImg.height(), GLTexture::FormatRGBA, GLTexture::Target2D);
    _userObject.setLightMapTexture(QSharedPointer<GLTexture>(lightTexture));
    lightTexture->setMagnificationFilter();
    lightTexture->setMinificationFilter(GLTexture::MinificationLinear);
    lightTexture->setSCoordinateWrap(GLTexture::WrapClampToEdge);
    lightTexture->setTCoordinateWrap(GLTexture::WrapClampToEdge);
}

void GLWidget::initializeGL()
{
    const char *vShaderStr =
            "attribute vec4 a_position;   \n"
            "attribute vec2 a_texCoord;   \n"
            "varying vec2 v_texCoord;     \n"
            "void main()                  \n"
            "{                            \n"
            "   gl_Position = a_position; \n"
            "   v_texCoord = a_texCoord;  \n"
            "}                            \n";

    const char *fShaderStr =
            "mediump float;                            \n"
            "varying vec2 v_texCoord;                            \n"
            "uniform sampler2D s_baseMap;                        \n"
            "uniform sampler2D s_lightMap;                       \n"
            "void main()                                         \n"
            "{                                                   \n"
            "  vec4 baseColor;                                   \n"
            "  vec4 lightColor;                                  \n"
            "                                                    \n"
            "  baseColor = texture2D( s_baseMap, v_texCoord );   \n"
            "  lightColor = texture2D( s_lightMap, v_texCoord ); \n"
            "  gl_FragColor = baseColor * (lightColor + 0.25);   \n"
            "}                                                   \n";

    // Load the shaders and get a linked program object
    _userObject.loadProgram(vShaderStr, fShaderStr);

    // Get the attribute locations
    _userObject.setPositionLocation(_userObject.programObject()->attributeLocation("a_position"));
    _userObject.setTexCoordLocation(_userObject.programObject()->attributeLocation("a_texCoord"));

    // Get the sampler locations

    _userObject.setBaseMapLocation(_userObject.programObject()->uniformLocation("s_baseMap"));
    _userObject.setLightMapLocation(_userObject.programObject()->uniformLocation("s_lightMap"));

//    _userObject.setSamplerLocation(_userObject.programObject()->uniformLocation("s_texture"));
    // Load the textures
    loadTextures();

    glClearColor ( 0.0f, 0.0f, 0.0f, 1.0f );
}

void GLWidget::paintGL()
{
    QVector<QVector3D> vertexCoords;
    vertexCoords.reserve(4);
    vertexCoords    << QVector3D(-0.5f, 0.5f, 0.0f)
                    << QVector3D(-0.5f, -0.5f, 0.0f)
                    << QVector3D(0.5f, -0.5f, 0.0f)
                    << QVector3D(0.5f, 0.5f, 0.0f);
    QVector<QVector2D> texCoords;
    texCoords.reserve(4);
    texCoords       << QVector2D(0.0f, 0.0f)
                    << QVector2D(0.0f, 1.0f)
                    << QVector2D(1.0f, 1.0f)
                    << QVector2D(1.0f, 0.0f);
    GLushort indices[] = { 0, 1, 2, 0, 2, 3 };

    // Set the viewport
    glViewport(0, 0, width(), height());

    // Clear the color buffer
    glClear ( GL_COLOR_BUFFER_BIT );

    // Use the program object
    _userObject.programObject()->bind();

    // Load the vertex position
    _userObject.programObject()->setAttributeArray(_userObject.positionLocation(), vertexCoords.constData());

    // Load the texture coordinates
    _userObject.programObject()->setAttributeArray(_userObject.texCoordLocation(), texCoords.constData());

    _userObject.programObject()->enableAttributeArray(_userObject.positionLocation());
    _userObject.programObject()->enableAttributeArray(_userObject.texCoordLocation());

    // Bind the basemap
    _userObject.baseMapTexture()->activate(0);
    _userObject.baseMapTexture()->bind();

    // Set the base map sampler to texture unit 0
    _userObject.programObject()->setUniformValue(_userObject.baseMapLocation(), 0);

    // Bind the lightmap
    _userObject.lightMapTexture()->activate(1);
    _userObject.lightMapTexture()->bind();

    // Set the light map sampler to texture unit 1
    _userObject.programObject()->setUniformValue(_userObject.lightMapLocation(), 1);

    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);
    int rc = glGetError();
    if (rc) qWarning() << "error in paintGL: " << rc;
}

void GLWidget::resizeGL(int width, int height)
{
    // nothing to do
    (void)width;
    (void)height;
}
